<?php

class lockManager{
	
	protected $lockTime = 0;
	
	function __construct(){
		$this->lockTime = sfConfig::get('app_fonctions_lockTime',20);
	}
	
	/*
	 * Sets the amount of time resources are locked
	 * @param integer $value   | time in minutes
	 * 
	 * */
	public function setLockTime( $value ){
		$this->lockTime = $value;
	}
	
	/*
	 * Locks an object for the $time period of time. If object already locked, returns false
	 * 
	 * @param sfDoctrineRecord $object
	 * 
	 * return resourcelock
	 *  
	 * */
	
	public function lockObject( sfDoctrineRecord $object){
		//Util::sendDebug('Antes de lockear el objeto');
		if($this->isObjectLocked($object)){
			return false;
		}else{
			return $this->createResourceLock($object);	
		}
	}
	
	/*
	 * Finish the locking of an object
	 * 
	 * @param sfDoctrineRecord $object
	 * @param boolean $forceRelease  | Si true, le lock is erased without taking care of lock's user_id
	 * return void
	 *  
	 * */
	
	
	public function releaseObject( sfDoctrineRecord $object, $forceRelease = false){
		$objectClass = get_class($object);
		$id = current($object->identifier());
		$q = Doctrine_Query::create()->from('resourcelock r');
		$q->addWhere('r.classname = ?', $objectClass);
		$q->addWhere('r.object_id = ?', $id);
		if(!$forceRelease){
			$q->addWhere('r.user_id = ?', current(sfContext::getInstance()->getUser()->getUserProfile()->identifier()));
			$q->addWhere('r.client_ip = ?', $this->getClientIP());
		}
		$result = $q->execute();
		foreach ($result as $item){
			$lock = $item;
		}
		if(isset($lock))
			$lock->delete();
	}
	
	/*
	 * Frees all objects granted to current user user
	 * 
	 * @param sfDoctrineRecord $object
	 * @param boolean $forceRelease  | Si true, le lock is erased without taking care of lock's user_id
	 * return void
	 *  
	 * */
	
	
	public function releaseAllObjects(){

		$q = Doctrine_Query::create()->from('resourcelock r');
		$q->addWhere('r.user_id = ?', current(sfContext::getInstance()->getUser()->getUserProfile()->identifier()));
		$q->addWhere('r.client_ip = ?', $this->getClientIP());

		$result = $q->execute();
		foreach ($result as $item){
			$lock = $item;
			$lock->delete();
		}
		
	}	
	
	/* Evals whether object is locked or not.
	 * Un object is not locked if:
	 * a-There is no record in the resourcelock table for this object
	 * b-The existing record in the resourcelock table for this object is outdated (it's too old)
	 * c-The existing record in the resourcelock table for this object has been granted to the same user and the same client's ip address
	 * 
	 * @param sfDoctrineRecord $object
	 * 
	 * return boolean
	 * 
	 * */
	
	public function isObjectLocked(sfDoctrineRecord $object){
		$objectClass = get_class($object);
		$id = current($object->identifier());
		$q = Doctrine_Query::create()->from('resourcelock r');
		$q->addWhere('r.classname = ?', $objectClass);
		$q->addWhere('r.object_id = ?', $id);
		$result = $q->execute();
		
		if($result->count()==0){
			return false;
		}else{
			foreach ($result as $item){
				$lock = $item;
			}
			if($lock->isOutdated()){
				$lock->delete();
				return false;
			}else{
				if($lock->user_id == current(sfContext::getInstance()->getUser()->getUserProfile()->identifier())
					&& $lock->client_ip == $this->getClientIP())
				{
					$lock->delete();
					return false;
				}else{
					return true;
				}
			}
		}
	}
	
	/* Returns lock's information
	 * 
	 *  @param sfDoctrineRecord $object
	 * 
	 * return array
	 * */
	
	public function whosLocking(sfDoctrineRecord $object){
		$objectClass = get_class($object);
		$id = current($object->identifier());
		$q = Doctrine_Query::create()->from('resourcelock r');
		$q->addWhere('r.classname = ?', $objectClass);
		$q->addWhere('r.object_id = ?', $id);
		$result = $q->execute();
		
		if($result->count()==0){
			return false;
		}else{
			foreach ($result as $lock){
				return $lock->toArray();
			}
		}
	}
	
	/* Creates resourcelock record for the given resource
	 * 
	 * @param object $resource
	 * 
	 * return resourcelock
	 * */
	
	private function createResourceLock($resource){
		$lock = new resourcelock();
		$lock->object_id = current($resource->identifier());
		$lock->classname = get_class($resource);
		$lock->locktime = $this->lockTime;
		try {
			$lock->username = sfContext::getInstance()->getUser()->getName();
			$lock->username = sfContext::getInstance()->getUser()->getUserName();	
		} catch (Exception $e) {
			
		}
		
		$lock->user_id = current(sfContext::getInstance()->getUser()->getUserProfile()->identifier());
		$lock->client_ip = $this->getClientIP();
		$lock->client_name = gethostbyaddr($lock->client_ip);
		$lock->save();
		return $lock;
	}
	
	/* Returns current client's IP.
	 * 
	 * return string
	 * */
	
	public static function getClientIP(){
		if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
	    	$IP = $_SERVER['HTTP_X_FORWARDED_FOR']; 
	    elseif(isset($_SERVER['HTTP_CLIENT_IP']))   
	    	$IP = $_SERVER['HTTP_CLIENT_IP'];   
	    else
	    	$IP = $_SERVER['REMOTE_ADDR'];
	    // affiche l'IP
	    return $IP;
	}
} 